/**
 * @file igs_task.c
 * @author Sheng Wen Peng
 * @date 25 Nov 2014
 * @brief IGS pulseDevice functions including
 *    pay out device  hopper
 *                    ticket
 *    pay in device   coin
 *    another         counter
 */
 
#include "igs_pulseDevice.h"

/**
 * @brief limit the max number of each device
 */
#define MAX_NUM_OF_PAYIN_DEVICE 16 //coin
#define MAX_NUM_OF_PAYOUT_DEVICE 16 //hopper, ticket
#define MAX_NUM_OF_COUNTER 16 //total, coin, service

#define INHABIT_PIN_ACTIVE_TYPE 1 /**< pay in device inhabit pin active type */

/**
 * @brief define the payout device state
 */
#define PAYOUT_DEVICE_OK 0 /**< hopper/ticket is ok */
#define PAYOUT_DEVICE_EMPTY 1 /**< hopper/ticket is empty */
#define PAYOUT_DEVICE_JAM 2 /**< hopper/ticket is jam */

//static uint32_t num_of_counter = 0;
//static uint32_t num_of_payOutDevice = 0;
//static uint32_t num_of_payInDevice = 0;

static uint8_t command[32]; /**< array for protocol command */

/**
 * @brief structure for coin
 */
struct PulseInDevice_t
{
	uint32_t IsErr; /**< device error flag */
	uint8_t IsEnable; /**< enable/disable this device */
	uint32_t input_IO_id; /**< input io id */
	uint32_t output_IO_id; /**< output io id (inhabit pin) */
	uint32_t counterActive; /**< counter for coin */
	
	/**
	 * @brief if the input signal length is between bouncingTime and activeTime,
	 *    it is a valid input.
	 */
	uint32_t min_of_confirm_range; /**<  */
	uint32_t max_of_confirm_range; /**<  */
	uint32_t jam_time; /**<  */
	uint8_t input_active_type; /**< low active (0) or high active (1) */
	uint8_t previousInValue; /**< we scan io per 2ms, this register contains save the last one io value */
}PulseInDevice[MAX_NUM_OF_PAYIN_DEVICE];

/**
 * @brief structure for ticket/hopper
 */
struct PulseOutDevice_t
{
	uint8_t IsEnable; /**< device error flag */
	uint32_t input_IO_id; /**< input io id */
	
	uint32_t output_IO_id_forward; /**< output io id  */ 
	uint32_t output_IO_id_backward; /**< output io id  */ 
	uint32_t value; /**< the pay out ticket/coin value */
	
	uint32_t counterResponse; /**< counter if the hopper is no action */
	uint32_t counterActive; /**< counter the input active signal */
	
	uint8_t input_active_type; /**< input io active type, low active (0) or high active (1) */
	uint8_t output_active_type; /**< output io active type, low active (0) or high active (1) */
	
	uint32_t jam_time;
	uint32_t responseTime; /**< if payout device is no response default 10s */
	
	/**
	 * @brief if the input signal length is between bouncingTime and activeTime,
	 *    it is a valid input.
	 */
	uint32_t min_of_confirm_range;
	uint32_t max_of_confirm_range;
	
	uint8_t previousInValue; /**< we scan io per 2ms, this register contains save the last one io value */

	/**
	 * @brief waveform timing spec          
	 */
	 
	 uint8_t wave_IsStart; 
	 uint32_t counterWaveform; /**< hopper pattern count */
	 uint32_t wave_forward_time;
	 uint32_t wave_stop_time;
	 uint32_t wave_backward_time;

}PulseOutDevice[MAX_NUM_OF_PAYOUT_DEVICE];

/**
 * @brief structure for counter
 */
struct Counter_t
{
	uint8_t IsEnable; /**< device error flag */
	uint32_t IO_id; /**< output io id */
	uint32_t value; /**< number of count still not count */
	uint32_t counter; /**< waveform count */
	
	/**
	 * @brief 
	 *    
	 *    low active
	 *    ----------|             |--------------|             |-------------
	 *              |  hold time  |  Setup time  |  hold time  |
	 *              |-------------|              |-------------|
	 *
	 *
	 *    high active
	 *                |-------------|              |-------------|
	 *                |  hold time  |  Setup time  |  hold time  |
	 *    ------------|             |--------------|             |------------
	 *
	 */
	uint32_t setupTime; /**< setup time */
	uint32_t holdTime; /**< hold time */
	uint32_t active_type; /**< low active (0) or high active (1) */
	
}Counter[MAX_NUM_OF_COUNTER];

/**
 * @brief local function prototypes
 */
static void counterRoutine(uint32_t elapstedTime);
static void counterHandler(void);
static void pulseDevicePinSet(uint32_t id, uint8_t activeType, uint32_t IsActive);

static void pulseDevice_counter_command(uint8_t *buf, uint32_t len);
static void pulseDevice_counterAddDevice(uint8_t *buf, uint32_t len);
static void pulseDevice_counterAddValue(uint8_t *buf, uint32_t len);

static void payDeviceHandler(void);

static void payOutRoutine(uint32_t elapstedTime);
static void pulseDevice_payOut_command(uint8_t *buf, uint32_t len);
static void pulseDevice_payOut_control(uint8_t *buf, uint32_t len);
static void pulseDevice_payOutAddDevice(uint8_t *buf, uint32_t len);

static void payInRoutine(uint32_t elapstedTime);
static void pulseDevice_payIn_command(uint8_t *buf, uint32_t len);
static void pulseDevice_payIn_control(uint8_t *buf, uint32_t len);
static void pulseDevice_payInAddDevice(uint8_t *buf, uint32_t len);

/**
 * @brief pulseDevicePinSet
 *    change the gpio id value accroding the value and active type
 * @pram id
 *    gpio id
 * @param activeType
 *    active type 0 is low active, 1 is high active
 * @param IsActive
 *    ENABLE (1) = active
 *    DISABLE (0) = inactive
 */
static void pulseDevicePinSet(uint32_t id, uint8_t activeType, uint32_t IsActive)
{
	if(activeType == 1)
	{
		if(IsActive == ENABLE)
			igs_gpio_set_out_real(id, 1);
		else
			igs_gpio_set_out_real(id, 0);
	}
	else
	{
		if(IsActive == ENABLE)
			igs_gpio_set_out_real(id, 0);
		else
			igs_gpio_set_out_real(id, 1);
	}
}

/**
 * @brief counterHandler
 *    counter handler need by igs task format
 * @param
 * @return
 */
static void counterHandler()
{
	counterRoutine(2);
}

/**
 *  @brief counterRoutine
 *     counter handler with the input parameter
 *  @param elapstedTime
 *     tell the function the period time (unit ms)
 *  @return
 */
static void counterRoutine(uint32_t elapstedTime)
{
	uint32_t i;
	uint32_t sumOfActiveTime;
	
	for(i=0;i<MAX_NUM_OF_COUNTER;i++)
	{
		sumOfActiveTime = Counter[i].setupTime + Counter[i].holdTime;

		if(Counter[i].value != 0)
		{
			Counter[i].counter += elapstedTime;
			
			//setup time
			if(Counter[i].counter < Counter[i].setupTime)
			{
				pulseDevicePinSet(Counter[i].IO_id, Counter[i].active_type, DISABLE);
			}
			//hold time
			else if(Counter[i].counter >= Counter[i].setupTime && Counter[i].counter < sumOfActiveTime)
			{
				pulseDevicePinSet(Counter[i].IO_id, Counter[i].active_type, ENABLE);
			}
			//over
			else if(Counter[i].counter >= sumOfActiveTime)
			{
				Counter[i].value--;
				Counter[i].counter = 0;
				pulseDevicePinSet(Counter[i].IO_id, Counter[i].active_type, DISABLE);
			}
		}
	}
}

/**
 * @brief pulseDevice_counter_command
 *    counter command handler
 * @param buf
 *   format:  buf[0] sub command
 *            buf[1] command content1
 *            buf[2] command content2
 *            buf[3]         .
 *            buf[4]         .
 *            buf[5]         .
 * @param len
 *    buf length
 *  @return
 */
static void pulseDevice_counter_command(uint8_t *buf, uint32_t len)
{
	switch(buf[0])
	{
		case COMMAND_COUNTER_INIT:
			pulseDevice_counterAddDevice(&buf[1],len-1);
			break;
		case COMMAND_COUNTER_ADD:
			pulseDevice_counterAddValue(&buf[1],len-1);
			break;
		default: break;
	}
}

/**
 * @brief pulseDevice_counterAddDevice
 *    counter add device
 * @param buf
 *   format:  buf[0] counter id
 *            buf[1] device enable(1)/disable(0)
 *            buf[2] high/low active
 *            buf[3] io id
 *            buf[4] the hold time
 *            buf[5] the setup time
 * @param len
 *    buf length
 *  @return
 */
static void pulseDevice_counterAddDevice(uint8_t *buf, uint32_t len)
{
	uint32_t id,io,setup,hold,tmp;
	
	if(buf[0] < MAX_NUM_OF_COUNTER)
	{
		tmp = buf[5];
		hold = buf[4] + (tmp << 8);
		
		tmp = buf[7];
		setup = buf[6] + (tmp << 8);
		id = buf[0];
		io = buf[3];
		
		Counter[id].IsEnable = buf[1]; //enable/disable
		Counter[id].IO_id = io; // IO
		Counter[id].value = 0;
		Counter[id].counter = 0;
		Counter[id].setupTime = setup;
		Counter[id].holdTime = hold;
		Counter[id].active_type= buf[2]; // active type
		pulseDevicePinSet(Counter[id].IO_id, Counter[id].active_type, DISABLE); //disable contorl pin
		igs_gpio_set_output_mask(io,DISABLE_GPIO_MASK);

	}
}

/**
 * @brief pulseDevice_counterAddValue
 *    add counter value
 * @param buf
 *   format:   buf[0] counter id 
 *             buf[1] value[7:0] 
 *             buf[2] value[15:8]
 * @param len
 *    buf length
 * @return
 */
static void pulseDevice_counterAddValue(uint8_t *buf, uint32_t len)
{
	uint32_t id,value;
	if(buf[0] < MAX_NUM_OF_COUNTER)
	{
		id = buf[0];
		value = buf[2];
		value = value << 8;
		value += buf[1];
		Counter[id].value += value;
	}
}

/**
 * @brief payDeviceHandler
 *    pay in out device handler with igs task interface
 * @param
 * @return
 */
static void payDeviceHandler()
{
	payInRoutine(2);
	payOutRoutine(2);
}

/**
 * @brief payOutRoutine
 *    pay out device handler with input
 * @param elapstedTime
 *    tell the function the period time (unit ms)
 * @return
 */
static void payOutRoutine(uint32_t elapstedTime)
{
	uint32_t i;
	uint8_t valueTmp;
	uint32_t wave_timing[4];
	for(i=0;i<MAX_NUM_OF_PAYOUT_DEVICE;i++)
	{
		if(PulseOutDevice[i].IsEnable != 1)
		{
			continue;
		}
		
		//error handle
		if(
			 PulseOutDevice[i].counterResponse > PulseOutDevice[i].responseTime ||
			 PulseOutDevice[i].counterActive > PulseOutDevice[i].jam_time) 
		{
			//empty, report error
			PulseOutDevice[i].IsEnable = 0;
			PulseOutDevice[i].wave_IsStart = 0;
			pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, DISABLE);
			pulseDevicePinSet(PulseOutDevice[i].output_IO_id_backward, PulseOutDevice[i].output_active_type, DISABLE);
			//pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, DISABLE); //disable contorl pin
			command[0] = COMMAND_DISPENSER; 
			command[1] = 4; // length
			command[2] = COMMAND_DISPENSER_CTL;
			command[3] = i; // id
			command[4] = 0; // no payout out
			if(PulseOutDevice[i].counterActive == 0)
				command[5] = PAYOUT_DEVICE_EMPTY; // empty
			else
				command[5] = PAYOUT_DEVICE_JAM; // jam
			
			igs_queue_push(IGS_QUEUE_TX_TYPE,command,6);
			continue;
		}
		
		
		if(PulseOutDevice[i].value != 0)
		{
			//need pay out
			PulseOutDevice[i].counterResponse += elapstedTime;
			PulseOutDevice[i].wave_IsStart = 1;
			//pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, ENABLE); //enable contorl pin
		}
		else
		{
			// idle
			PulseOutDevice[i].wave_IsStart = 0;
			//pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, DISABLE); //disable contorl pin
		}
		
		
		// catch input value
		valueTmp = igs_gpio_get_in_real(PulseOutDevice[i].input_IO_id);
		
		
		// if input value now is active, counter add
		if(valueTmp == PulseOutDevice[i].input_active_type)
		{
			PulseOutDevice[i].counterActive += elapstedTime;
		}
		
		if(
			valueTmp != PulseOutDevice[i].previousInValue && // input value is different
			 valueTmp != PulseOutDevice[i].input_active_type) // and now is inactive
		{
			if(PulseOutDevice[i].counterActive > PulseOutDevice[i].min_of_confirm_range &&
				 PulseOutDevice[i].counterActive < PulseOutDevice[i].max_of_confirm_range)
			{
				//valid input
				PulseOutDevice[i].counterResponse = 0;

				
				//PulseOutDevice[i].counterWaveform = 0;
				if(PulseOutDevice[i].value != 0)
					PulseOutDevice[i].value--;
				if(PulseOutDevice[i].value == 0)
					PulseOutDevice[i].wave_IsStart = 0;

					
				command[0] = COMMAND_DISPENSER; 
				command[1] = 4; // length
				command[2] = COMMAND_DISPENSER_CTL;
				command[3] = i; // id
				command[4] = 1; // 1 payout out
				command[5] = PAYOUT_DEVICE_OK; // no error
				igs_queue_push(IGS_QUEUE_TX_TYPE,command,6);
			}

			PulseOutDevice[i].counterActive = 0;
		}
		
		PulseOutDevice[i].previousInValue = valueTmp;
		
    //
		// waveform generate
		//
		if(PulseOutDevice[i].wave_IsStart == 1)
		{
			
			PulseOutDevice[i].counterWaveform += elapstedTime;
			
			wave_timing[0] = PulseOutDevice[i].wave_forward_time;
			wave_timing[1] = wave_timing[0] + PulseOutDevice[i].wave_stop_time;
			wave_timing[2] = wave_timing[1] + PulseOutDevice[i].wave_backward_time;
			wave_timing[3] = wave_timing[2] + PulseOutDevice[i].wave_stop_time;
			
			if(PulseOutDevice[i].counterWaveform < wave_timing[0])
			{
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, ENABLE);
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_backward, PulseOutDevice[i].output_active_type, DISABLE);
			}
			else if(PulseOutDevice[i].counterWaveform < wave_timing[1])
			{
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, DISABLE);
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_backward, PulseOutDevice[i].output_active_type, DISABLE);
			}
			else if(PulseOutDevice[i].counterWaveform < wave_timing[2])
			{
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, DISABLE);
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_backward, PulseOutDevice[i].output_active_type, ENABLE);
			}
			else if(PulseOutDevice[i].counterWaveform < wave_timing[3])
			{
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, ENABLE);
				pulseDevicePinSet(PulseOutDevice[i].output_IO_id_backward, PulseOutDevice[i].output_active_type, DISABLE);
			}
			else
			{
				PulseOutDevice[i].counterWaveform = 0;
			}
		}
		else
		{
			PulseOutDevice[i].counterWaveform = 0;
			pulseDevicePinSet(PulseOutDevice[i].output_IO_id_forward, PulseOutDevice[i].output_active_type, DISABLE);
			pulseDevicePinSet(PulseOutDevice[i].output_IO_id_backward, PulseOutDevice[i].output_active_type, DISABLE);
		}
	}
}

/**
 * @brief pulseDevice_payOut_command
 *    pay out device control command handler
 * @param buf
 *   format:   buf[0] sub command
 *             buf[1] command content1
 *             buf[2] command content2
 *             buf[3] command content3
 * @param len
 *    buf length
 */
static void pulseDevice_payOut_command(uint8_t *buf, uint32_t len)
{
	switch(buf[0])
	{
		case COMMAND_DISPENSER_INIT:
			pulseDevice_payOutAddDevice(&buf[1], len-1);
			break;
		case COMMAND_DISPENSER_CTL:
			pulseDevice_payOut_control(&buf[1],len-1);
			break;
		default: break;
	}
}

/**
 * @brief pulseDevice_payOut_control
 *    pay out device control command handler
 * @param buf
 *   format:   buf[0] device id
 *             buf[1] pay out value[7:0]
 *             buf[2] pay out value[15:8]
 *             buf[3] reset flag, 1 is active
 * @param len
 *    buf length
 */
static void pulseDevice_payOut_control(uint8_t *buf, uint32_t len)
{
	uint32_t id,value;
	if(buf[0] < MAX_NUM_OF_PAYOUT_DEVICE)
	{
		id = buf[0];
		value = buf[2];
		value = value << 8;
		value += buf[1];
		
		// reset
		if(buf[3] == 1) 
		{
			PulseOutDevice[id].value = 0;
			PulseOutDevice[id].counterResponse = 0;
			PulseOutDevice[id].counterWaveform = 0;
			PulseOutDevice[id].counterActive = 0;
			return;
		}
		PulseOutDevice[id].value += value;
	}
}

/**
 * @brief pulseDevice_payOutAddDevice
 *    pay out device add
 * @param buf
 *    format:   buf[0] device id
 *              buf[1] enable(1)/disable(0)
 *              buf[2] output active type
 *              buf[3] input io id
 *              buf[4] output io id (forward)
 *              buf[5] output io id (backward)
 *              buf[6] min_of_confirm_range[7:0]
 *              buf[7] min_of_confirm_range[15:8]
 *              buf[8] max_of_confirm_range[7:0]
 *              buf[9] max_of_confirm_range[15:8]
 *              buf[10] device no response time value[7:0]
 *              buf[11] device no response time value[15:8]
 *              buf[12] jam_time[7:0]
 *              buf[13] jam_time[15:8]
 *              buf[14] wave_forward_time[7:0]
 *              buf[15] wave_forward_time[15:8]
 *              buf[16] wave_stop_time[7:0]
 *              buf[17] wave_stop_time[15:8]
 *              buf[18] wave_backward_time[7:0]
 *              buf[19] wave_backward_time[15:8]
 * @param len
 *    buf length
 * @return
 */
static void pulseDevice_payOutAddDevice(uint8_t *buf, uint32_t len)
{
	uint32_t id,tmp,io_f,io_b,io_in;
	uint32_t wave_forward_time;
	uint32_t wave_stop_time;
	uint32_t wave_backward_time;
	if(buf[0] < MAX_NUM_OF_PAYOUT_DEVICE)
	{
		
		id = buf[0];
		io_f = buf[4];
		io_b = buf[5];
		io_in = buf[3];
		PulseOutDevice[id].wave_IsStart = 0;
		PulseOutDevice[id].IsEnable = buf[1];
		PulseOutDevice[id].input_IO_id = io_in;
		PulseOutDevice[id].output_IO_id_forward = io_f;
		PulseOutDevice[id].output_IO_id_backward = io_b;
		PulseOutDevice[id].value = 0;
		PulseOutDevice[id].counterResponse = 0;
		PulseOutDevice[id].counterActive = 0;
		PulseOutDevice[id].counterWaveform = 0;
		
		tmp = buf[17];
		tmp = tmp << 8;
		tmp += buf[16];
		PulseOutDevice[id].jam_time = tmp;
		
		tmp = buf[11];
		tmp = tmp << 8;
		tmp += buf[10];
		wave_forward_time = tmp;
		PulseOutDevice[id].wave_forward_time = wave_forward_time;
		
		tmp = buf[15];
		tmp = tmp << 8;
		tmp += buf[14];
		wave_stop_time = tmp;
		PulseOutDevice[id].wave_stop_time = wave_stop_time;
		
		tmp = buf[13];
		tmp = tmp << 8;
		tmp += buf[12];
		wave_backward_time = tmp;
		PulseOutDevice[id].wave_backward_time = wave_backward_time;
		
		PulseOutDevice[id].responseTime = wave_backward_time + wave_stop_time + wave_forward_time;
		PulseOutDevice[id].responseTime *= 3;
		
		tmp = buf[7];
		tmp = tmp << 8;
		tmp += buf[6];
		PulseOutDevice[id].min_of_confirm_range = tmp;
		
		tmp = buf[9];
		tmp = tmp << 8;
		tmp += buf[8];
		PulseOutDevice[id].max_of_confirm_range = tmp;

		PulseOutDevice[id].input_active_type = buf[2]?0:1;
		PulseOutDevice[id].output_active_type = 1;
		PulseOutDevice[id].previousInValue = buf[2]?1:0;
		
		pulseDevicePinSet(PulseOutDevice[id].output_IO_id_forward, PulseOutDevice[id].output_active_type,DISABLE); //disable contorl pin
		pulseDevicePinSet(PulseOutDevice[id].output_IO_id_backward, PulseOutDevice[id].output_active_type,DISABLE); //disable contorl pin
		
		igs_gpio_set_input_mask(io_in,DISABLE_GPIO_MASK);
		igs_gpio_set_output_mask(io_f,DISABLE_GPIO_MASK);
		igs_gpio_set_output_mask(io_b,DISABLE_GPIO_MASK);
	}
}

/**
 * @brief payInRoutine
 *    pay in device handler with time input
 * @param elapstedTime
 *    period function time
 * @return
 */
static void payInRoutine(uint32_t elapstedTime)
{
	uint32_t i;
	uint8_t valueTmp;
	for(i=0;i<MAX_NUM_OF_PAYIN_DEVICE;i++)
	{
		if(PulseInDevice[i].IsEnable != 1)
		{
			continue;
		}
		
		// error occur
		if(PulseInDevice[i].counterActive > PulseInDevice[i].jam_time)
		{
			PulseInDevice[i].IsErr = 1;
		}
		
		// catch input value
		valueTmp = igs_gpio_get_in_real(PulseInDevice[i].input_IO_id);
		
		// counter add when the input is active
		if(valueTmp == PulseInDevice[i].input_active_type)
		{
			PulseInDevice[i].counterActive += elapstedTime;
		}
		
		if(
			valueTmp != PulseInDevice[i].previousInValue && // value is different
			 valueTmp != PulseInDevice[i].input_active_type) // and now is inactive
		{
			if(PulseInDevice[i].counterActive > PulseInDevice[i].min_of_confirm_range &&
				 PulseInDevice[i].counterActive < PulseInDevice[i].max_of_confirm_range   )
			{
				//valid input
				command[0] = COMMAND_ACCEPT; 
				command[1] = 4; // length
				command[2] = COMMAND_ACCEPT_CTL;
				command[3] = i; // id
				command[4] = 1; // 1 payout in
				command[5] = PulseInDevice[i].IsErr; // error flag
				igs_queue_push(IGS_QUEUE_TX_TYPE,command,6);
			}

			PulseInDevice[i].counterActive = 0;
		}
		PulseInDevice[i].previousInValue = valueTmp;
	}
}

static void pulseDevice_payIn_command(uint8_t *buf, uint32_t len)
{
	switch(buf[0])
	{
		case COMMAND_ACCEPT_INIT:
			pulseDevice_payInAddDevice(&buf[1],len-1);
			break;
		case COMMAND_ACCEPT_CTL:
			pulseDevice_payIn_control(&buf[1],len-1);
			break;
		default:
			break;
	}
}

/**
 * @brief pulseDevice_payIn_control
 *    pay in device control command handler
 * @param buf
 *   format:   buf[0] device id
 *             buf[1] clear err
 *             buf[2] inhibit pin control
 * @param len
 *    buf length
 */
static void pulseDevice_payIn_control(uint8_t *buf, uint32_t len)
{
	uint32_t id;
	if(buf[0] < MAX_NUM_OF_PAYIN_DEVICE)
	{
		id = buf[0];
		
		// clear err
		if(buf[1] == 1) 
		{
			PulseInDevice[id].IsErr = 0;
		}
		if(buf[2] == 1) 
		{
			pulseDevicePinSet(PulseInDevice[id].output_IO_id, INHABIT_PIN_ACTIVE_TYPE,DISABLE); //disable contorl pin
		}
		else
		{
			pulseDevicePinSet(PulseInDevice[id].output_IO_id, INHABIT_PIN_ACTIVE_TYPE,DISABLE); //disable contorl pin
		}
	}
}

/**
 * @brief pulseDevice_payInAddDevice
 *    pay out device add
 * @param buf
 *    format:   buf[0] device id
 *              buf[1] enable(1)/disable(0)
 *              buf[2] input active type
 *              buf[3] input io id
 *              buf[4] output io id (inhabit pin)
 *              buf[5] min_of_confirm_range[7:0]
 *              buf[6] min_of_confirm_range[15:8]
 *              buf[7] max_of_confirm_range[7:0]
 *              buf[8] max_of_confirm_range[15:8]
 *              buf[9] jam time value[7:0] 
 *              buf[10] jam time value[15:8] 
 * @param len
 *    buf length
 * @return
 */
static void pulseDevice_payInAddDevice(uint8_t *buf, uint32_t len)
{
	uint32_t id;
	if(buf[0] < MAX_NUM_OF_PAYIN_DEVICE)
	{
		id = buf[0];
		PulseInDevice[id].IsEnable = buf[1];
		PulseInDevice[id].IsErr = 0;
		PulseInDevice[id].input_IO_id = buf[3];
		PulseInDevice[id].output_IO_id = buf[4];
		PulseInDevice[id].counterActive = 0;
		
		PulseInDevice[id].min_of_confirm_range = buf[5];
		PulseInDevice[id].max_of_confirm_range = buf[6];
		PulseInDevice[id].jam_time = buf[7];
		
		PulseInDevice[id].input_active_type = buf[2]?0:1;
		PulseInDevice[id].previousInValue = buf[2]?1:0;
		igs_gpio_set_output_mask(PulseInDevice[id].output_IO_id ,DISABLE_GPIO_MASK);
		igs_gpio_set_input_mask(buf[3],DISABLE_GPIO_MASK);
	}
}

/**
 * @brief igs_pulseDevice_init
 *    igs pulseDevice init
 * @param
 * @return
 */
void igs_pulseDevice_init()
{

	igs_task_add(IGS_TASK_ROUTINE_POLLING, 2,counterHandler);
	igs_task_add(IGS_TASK_ROUTINE_POLLING, 2,payDeviceHandler);

	igs_protocol_command_register(COMMAND_COUNTER,pulseDevice_counter_command);
	igs_protocol_command_register(COMMAND_ACCEPT,pulseDevice_payIn_command);
	igs_protocol_command_register(COMMAND_DISPENSER,pulseDevice_payOut_command);

	
	
}
